<!DOCTYPE HTML>
<html lang="en">
<head>
<title>StreamDevice: Record Processing</title>
<meta charset="utf-8" />
<link rel="shortcut icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="stream.css" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="author" content="Dirk Zimoch" />
</head>
<body>
<iframe src="nav.html" id="navleft"></iframe>
<h1>Record Processing</h1>

<a name="proc"></a>
<h2>1. Normal Processing</h2>
<p>
<em>StreamDevice</em> is an
<a href="https://docs.epics-controls.org/en/latest/appdevguide/deviceSupport.html#synchronous-vs-asynchronous-device-support"
target="ex">asynchronous device support</a>.
Whenever the record is processed, the <a href="protocol.html">protocol</a>
is scheduled to start and the record is left active (<code>PACT=1</code>).
The protocol itself runs in another thread.
That means that any waiting in the protocol does not delay any other
part of the IOC.
</p>
<p>
After the protocol has finished, the record is processed again, leaving
<code>PACT=0</code> this time, triggering monitors and processing
the forward link <code>FLNK</code>.
Note that input links with PP flag pointing to a <em>StreamDevice</em>
record will read the <u>old</u> value first and start the protocol
afterward.
This is a problem all asynchronous EPICS device supports have.
</p>
<p>
The first <code>out</code> command in the protocol locks the device
for exclusive access.
That means that no other record can communicate with that device.
This ensures that replies given by the device reach the record
which has sent the request.
On a bus with many devices on different addresses, this
normally locks only one device.
The device is unlocked when the protocol terminates.
Another record trying to lock the same device has to wait and
might get a <code>LockTimeout</code>.
<p>
</p>
<p>If any error happens, the protocol is aborted. The record will have
its <code>SEVR</code> field set to <code>INVALID</code> and its
<code>STAT</code> field to something describing the error:
</p>
<dl>
 <dt><code>TIMEOUT</code></dt>
 <dd>
  The device could not be locked (<code>LockTimeout</code>) because
  other records are keeping the device busy or the device did not reply
  in time (<a href="protocol.html#sysvar"><code>ReplyTimeout</code></a>).
 </dd>
 <dt><code>WRITE</code></dt>
 <dd>
  Output could not be written to the device in time
  (<a href="protocol.html#sysvar"><code>WriteTimeout</code></a>).
 </dd>
 <dt><code>READ</code></dt>
 <dd>
  Input from the device started but stopped unexpectedly
  (<a href="protocol.html#sysvar"><code>ReadTimeout</code></a>).
 </dd>
 <dt><code>COMM</code></dt>
 <dd>
  The device driver reported that the device is disconnected.
 </dd>
 <dt><code>CALC</code></dt>
 <dd>
  Input did not match the argument string of the <code>in</code> command
  or it contained values the record did not accept.
 </dd>
 <dt><code>UDF</code></dt>
 <dd>
  Some fatal error happened or the record has not been initialized
  correctly (e.g. because the protocol is erroneous).
 </dd>
</dl>

<p>
If the protocol is aborted, an
<a href="protocol.html#except">exception handler</a> might be executed
if defined.
Even if the exception handler can complete with no further error, the
protocol will not resume and <code>SEVR</code> and <code>STAT</code>
will be set according to the original error.
</p>

<a name="init"></a>
<h2>2. Initialization</h2>
<p>
Often, it is useful to initialize records from the hardware after
booting the IOC, especially output records.
For this purpose, initialization is formally handled as an
<a href="protocol.html#except">exception</a>.
The <code>@init</code> handler is called as part of the
<code>initRecord()</code> function during <code>iocInit</code>
before any scan task starts <span class="new">and may be re-run
later under circumstances listed below</span>.
</p>
<p>
In contrast to <a href="#proc">normal processing</a>, the protocol
is handled synchronously.
That means that <code>initRecord()</code> does not return before the
<code>@init</code> handler has finished.
Thus, the records initialize one after the other.
The scan tasks are not started and <code>iocInit</code> does not
return before all <code>@init</code> handlers have finished.
If the handler fails, the record remains uninitialized:
<code>UDF=1</code>, <code>SEVR=INVALID</code>,
<code>STAT=UDF</code>.
</p>
<p>
The <code>@init</code> handler has nothing to do with the
<code>PINI</code> field.
The handler does <u>not</u> process the record nor does it trigger
forward links or any links with the <code>PP</code> flag.
It runs <u>before</u> <code>PINI</code> is handled.
If the record has <code>PINI=YES</code>, the <code>PINI</code>
processing is a <a href="#proc">normal processing</a> after the
<code>@init</code> handlers of all records have completed.
</p>
<p>
Depending on the record type, format converters might work
slightly different from normal processing.
Refer to the description of
<a href="recordtypes.html">supported record types</a> for details.
</p>
<p>
If the <code>@init</code>handler has read a value and has completed
without error, the record starts in a defined state.
That means <code>UDF=0</code>, <code>SEVR=NO_ALARM</code>,
<code>STAT=NO_ALARM</code> and the <code>VAL</code> field contains
the value read from the device.
</p>
<p>
If no <code>@init</code> handler is installed, <code>VAL</code> and
<code>RVAL</code> fields remain untouched.
That means they contain the value defined in the record definition,
read from a constant <code>INP</code> or <code>DOL</code> field,
or restored from a bump-less reboot system
(e.g. <em>autosave</em> from the <em>synApps</em> package).
</p>
<p>
  The <code>@init</code> handler is called in the following situations:
  <ul>
    <li>At startup by <code>iocInit</code> during record initialization
        as described above.
    <li class="new">When the IOC is resumed with <code>iocRun</code> (after
        beeing paused with <code>iocPause</code>) before the scan tasks
        restart and before records with <code>PINI=RUN</code> are processed.
    <li class="new">When the protocol is
        <a href="setup.html#reload">reloaded</a></span> for example with
        <code>streamReload ["<var>recordname</var>"]</code>.
    <li class="new">When <em>StreamDevice</em> detects that the device has
        reconnected (after being disconnected). This includes the case that
        the device was disconnected when the IOC started.
        Be aware that some drivers test the connection only periodically,
        e.g. the <em>asynIPPort</em> driver tests it every few seconds.
        Thus there may be a small delay between the device being online
        and the record re-initializing.
    <li class="new">When <code>streamReinit
        "<var>asynPortname</var>"[,<var>addr</var>]</code> is called
        (if using an <em>asynDriver</em> port).
    <li class="new">When the "magic value" <code>2</code> is written to the
        <code>.PROC</code> field of the record.
        In this case the record is processed and thus its <code>FLNK</code>
        and links with the <code>PP</code> flag are triggered.
  </ul>
</p>

<a name="iointr"></a>
<h2>3. I/O Intr</h2>
<p>
<em>StreamDevice</em> supports I/O event scanning.
This is a mode where record processing is triggered by the device
whenever the device sends input.
</p>
<p>
In terms of protocol execution this means:
When the <code>SCAN</code> field is set to <code>I/O Intr</code>
(during <code>iocInit</code> or later),
the protocol starts without processing the record.
With the first <code>in</code> command, the protocol is suspended.
If the device has been locked (i.e there was an <code>out</code>
command earlier in the protocol), it is unlocked now.
That means that other records can communicate to the device while
this record is waiting for input.
This <code>in</code> command ignores <code>replyTimeout</code>,
it waits forever.
</p>
<p>
The protocol now receives any input from the device.

It also gets a copy of all input directed to other records.
Non-matching input does not generate a mismatch
<a href="protocol.html#except">exception</a>.
It just restarts the <code>in</code> command until matching input
is received.
</p>
<p>
After receiving matching input, the protocol continues normally.
All other <code>in</code> commands are handled normally.
When the protocol has completed, the record is processed.
It then triggers monitors, forward links, etc.
After the record has been processed, the protocol restarts.
</p>
<p>
This mode is useful in two cases:
First for devices that send data automatically without being asked.
Second to distribute multiple values in one message to different
records.
In this case, one record would send a request to the device and pick
only one value out of the reply.
The other values are read by records in <code>I/O Intr</code> mode.
</p>

<h3>Example:</h3>

<p>
Device <em>dev1</em> has a "region of interest" (ROI) defined by
a start value and an end value. When asked "<code>ROI?</code>",
it replies something like "<code>ROI 17.3 58.7</code>",
i.e. a string containing both values.
</p>
<p>
We need two ai records to store the two values. Whenever record
<code>ROI:start</code> is processed, it requests ROI from the device.
Record <code>ROI:end</code> updates automatically.
</p>
<pre>
record (ai "ROI:start") {
    field (DTYP, "stream")
    field (INP,  "@myDev.proto getROIstart dev1")
}
record (ai "ROI:end") {
    field (DTYP, "stream")
    field (INP,  "@myDev.proto getROIend dev1")
    field (SCAN, "I/O Intr")
}
</pre>
<p>
Only one of the two protocols sends a request, but both read
their part of the same reply message.
</p>
<pre>
getROIstart {
    out "ROI?";
    in  "ROI %f %*f";
}
getROIend {
    in  "ROI %*f %f";
}
</pre>
<p>
Note that the other value is also parsed by each protocol, but skipped
because of the <code>%*</code> <a href="formats.html">format</a>.
Even though the <code>getROIend</code> protocol may receive input
from other requests, it silently ignores every message that does not start
with "<code>ROI</code>", followed by two floating point numbers.
</p> 

<footer>
<a href="recordtypes.html">Next: Supported Record Types</a>
Dirk Zimoch, 2018
</footer>
</body>
</html>
